import com.sun.org.apache.xml.internal.utils.SystemIDResolver;

import java.util.InputMismatchException;
import java.util.Scanner;

class Person implements Cloneable{
    public int id;

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}

//      异常    如果不处理异常 那么这个异常会交给JVM处理 一旦交给JVM处理程序立马终止
public class TestDemo {
    public static void main1(String[] args) throws CloneNotSupportedException {
//        1.
//        System.out.println(10/0);    ArithmeticException    / by zero
//        2.
//        String str = null;
//        System.out.println(str.length());      NullPointerException
//        3.
//        int[] arr = {12,32,34};
//        System.out.println(arr[10]);          ArrayIndexOutOfBoundsException
//        4.clone 得实现Cloneable接口  重写Object方法才能克隆
//        Person person = new Person();
//        Person person1 = (Person) person.clone();//鼠标悬停clone抛出异常 因为放回类型是Object 使用要类型转换
//        5.
    }


    public static void main2(String[] args) {
//        6.
        Scanner scanner = new Scanner(System.in);
        int n = scanner.nextInt();
        System.out.println(n);//输入的不是整数 就会异常InputMismatchException
    }


    public static void main3(String[] args) {
//        int[] array = {12,23,34};
//        System.out.println(array[10]);
//        System.out.println("hello world");//上面代码错误下面的代码就不会执行了

        int[] array = {12, 23, 34};
        try {//放可能出现异常的代码
            System.out.println(array[10]);
            System.out.println("asd");//当抛出异常后 这一行就不会执行了
        } catch (ArrayIndexOutOfBoundsException e) {
//            1.
//            括号内这可以这样写(Exception e)但是不建议 因为异常太多了我们不知道发生什么异常
//            Exception是所有异常的父类 因此可以用这个类型表示捕捉所有异常 最好是捕获具体的异常类型
//            2.
//            ArrayIndexOutOfBoundsException这是一个类型 定义一个变量e
//            3.备注: catch 进行类型匹配的时候, 不光会匹配相同类型的异常对象,也会捕捉目标异常类型的子类对象.
//            如刚才的代码, NullPointerException 和 ArrayIndexOutOfBoundsException 都是 Exception 的子类,、
//            因此都能被捕获到.

//            e.printStackTrace();//熟悉的红色异常又回来了
            System.out.println("数组越界异常");
        }
        System.out.println("hello world");
//        打印结果：
//          数组越界异常
//          hello world
    }


    public static void main4(String[] args) {
        int[] array = {12, 23, 34};
        try {
            array = null;
            System.out.println(array[10]);
            //NullPointerException catch没捕捉到 然后交给JVM来处理
//            我们知道catch可能抛出多个异常 所以我们可以继续进行catch捕捉
            System.out.println("asd");
        } catch (ArrayIndexOutOfBoundsException e) {
            e.printStackTrace();
            System.out.println("捕捉到数组越界异常");
        } catch (NullPointerException e) {
            e.printStackTrace();
            System.out.println("捕捉到空指针异常");
        }//还可以在括号立马 用|来表示
//        (ArrayIndexOutOfBoundsException | NullPointerException e)
        System.out.println("hello world");
    }

//      注：
//      当try中发生异常之后 你要在对应的catch里面捕捉对应的异常
//      如果你没有捕捉这个异常 那么就会交给JVM处理 一旦交给JVM处理 程序立马就终止了


    //    catch在捕获异常的时候 从上往下
//    最好是 子类-》父类  (看异常父子类  鼠标点击异常右键-diagrams-里面两个都可以 )
//    不能   父类-》子类
    public static void main5(String[] args) {
        int[] array = {12, 2, 34};
        try {
            System.out.println(array[10]);
            System.out.println("asd");
        } catch (ArrayIndexOutOfBoundsException e) {
            System.out.println("捕捉到数组越界异常");
        } catch (IndexOutOfBoundsException e) {
            System.out.println("捕捉到异常");
        }
        System.out.println("hello world");
    }
//    如果是父类-》子类 会报错
//    打印结果：
//    捕捉到数组越界异常
//    hello world


    //    clone异常处理
    public static void main6(String[] args) {
        Person person = new Person();
        try {
            Person person1 = (Person) person.clone();
            //main后面没有抛出异常处理  我们可以使用try catch
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
    }


    //    finally 表示最后的善后工作, 例如释放资源
    public static void main7(String[] args) {
        Scanner scanner = new Scanner(System.in);
        try {
            int n = scanner.nextInt();//可能出异常
            System.out.println("10/" + n + "=" + 10.0 / n);
            System.out.println("10/" + n + "=" + String.format("%.2f", 10.0 / n));//保留两位小数
        } catch (InputMismatchException e) {
            e.printStackTrace();
            System.out.println("输入有误");
        } catch (ArithmeticException e) {
            e.printStackTrace();
            System.out.println("算数异常 可能0为余数了");
        } finally {//不管是否发生异常 都会执行
//            一般作用 资源的关闭
            scanner.close();//scanner属于一种资源 打开需要关闭
            System.out.println("finally执行了");
        }
//        打印：
//          123
//          10/123=0.08130081300813008
//          10/123=0.08
//          finally执行了
    }


    //      也可以将资源放到try(里面)  这样finally就不用释放资源了
    public static void main8(String[] args) {
        try (Scanner scanner = new Scanner(System.in)) {
            int n = scanner.nextInt();
            System.out.println("10/" + n + "=" + 10.0 / n);
        } catch (InputMismatchException e) {
            System.out.println("输入有误");
        } catch (ArithmeticException e) {
            System.out.println("算数异常 可能0为余数了");
        } finally {
            System.out.println("finally执行了");
        }
    }


    //    异常会沿着异常的信息调用栈进行传递
//    下面代码 下在 func栈处理 处理不了-》main-》JVM
    public static void func(int n) {
//        try {
//            System.out.println(10/n);
//        }catch (ArithmeticException e){
//            e.printStackTrace();
//        }
        System.out.println(10 / n);
    }

    public static void main9(String[] args) {
        try {
            func(0);
        } catch (ArithmeticException e) {
            e.printStackTrace();
        }
        System.out.println("asdfasd");
    }
//    打印结果
//    ArithmeticException
//    asdfasd


    public static void func1(int n) throws ArithmeticException {//throws 提示调用函数的人
        try {
            System.out.println(10 / n);
        } catch (ArithmeticException e) {
            System.out.println("func1()");
            e.printStackTrace();
        }
        System.out.println(10 / n);
    }

    public static void main10(String[] args) {
        try {
            func1(0);
        } catch (ArithmeticException e) {
            System.out.println("main");
            e.printStackTrace();
        }
        System.out.println("asdfasd");
    }
//    打印结果：
//      func1()
//      main
//      asdfasd
//      ArithmeticException 203
//      ArithmeticException 208



    public static int func3(){
        int a = 10;
        try {
            return a;
        }catch (ArithmeticException e) {
            e.printStackTrace();
        }finally {//尽量避免在fina当中写return
            return 20;
        }
    }
    public static void main11(String[] args) {
        System.out.println(func3());//20
    }


//    异常处理流程 程序先执行 try 中的代码
//    如果 try 中的代码出现异常, 就会结束 try 中的代码, 看和 catch 中的异常类型是否匹配.
//    如果找到匹配的异常类型, 就会执行 catch 中的代码
//    如果没有找到匹配的异常类型, 就会将异常向上传递到上层调用者. eg(交给main函数了)
//    无论是否找到匹配的异常类型, finally 中的代码都会被执行到(在该方法结束之前执行).
//    如果上层调用者也没有处理的了异常, 就继续向上传递.
//    一直到 main 方法也没有合适的代码处理异常, 就会交给 JVM 来进行处理, 此时程序就会异常终止.
//    1.顶层类 Throwable 派生出两个重要的子类, Error 和 Exception
//    2.其中 Error 指的是 Java 运行时内部错误和资源耗尽错误. 应用程序不抛出此类异常. 这种内部错误一旦出现，
//    除了告知用户并使程序终止之外, 再无能无力. 这种情况很少出现.
//    3.Exception 是我们程序猿所使用的异常类的父类.
//    4.其中 Exception 有一个子类称为 RuntimeException, 这里面又派生出很多我们常见的异常类
//    NullPointerException, IndexOutOfBoundsException 等.
//
//
//    Java语言规范将派生于 Error 类或 RuntimeException 类的所有异常称为   非受查异常(fun函数递归)   , 所有的其他异常称为    受查异常.
//    如果一段代码可能抛出 受查异常, 那么必须显式进行处理.

//    我们在处理异常的时候, 通常希望知道这段代码中究竟会出现哪些可能的异常.
//    我们可以使用 throws 关键字, 把可能抛出的异常显式的标注在方法定义的位置. 从而提醒调用者要注意捕获这些异常
    public static double func4(int x, int y) throws ArithmeticException{//这里是throws可以理解为声明
        if (y == 0){
            throw new ArithmeticException("抛出除 0 异常");
//            throw 手动抛出异常(自定义异常)
        }
        return x  * 1.0 / y;
    }
    public static void main12(String[] args) {
        System.out.println(func4(10,0));
//        打印结果：
//          Exception in thread "main" java.lang.ArithmeticException: 抛出除 0 异常
//	        at TestDemo.func4(TestDemo.java:245)
//	        at TestDemo.main(TestDemo.java:251)
    }


}